package com.snails.net.utils;

import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.text.TextUtils;

import androidx.annotation.Nullable;
import androidx.annotation.RawRes;

import com.snails.logger.Logger;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;

/**
 * Created by lawrence
 */

public class FileUtil {
    // SD卡根目录
    private static final String SDCARD_DIR = Environment.getExternalStorageDirectory().getPath();
    //系统相机目录
    public static final String CAMERA_PHOTO_DIR = Environment
            .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath() + "/Camera/";

    /**
     * @return true-SD卡可用，false-SD卡不可用
     */
    public static boolean isSdCardExist() {
        return Environment.MEDIA_MOUNTED
                .equals(Environment.getExternalStorageState());
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的cache文件夹；
     * SD卡不可用下，返回内存存储应用下的cache文件夹；
     */
    public static File appCacheFolder(Context ctx) {
        if (ctx != null) {
            if (!isSdCardExist())
                return ctx.getCacheDir();
            else
                return ctx.getExternalCacheDir();
        }
        return null;
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的files->cache文件夹；
     * SD卡不可用下，返回内存存储应用下的files->cache文件夹；
     */
    public static File appCreateFolder(Context ctx, String folderName) {
        if (ctx != null) {
            File file = null;
            if (isSdCardExist()) {
                // SD卡 files -> cache
                file = ctx.getExternalFilesDir(null);
                if (file == null) { file = ctx.getExternalCacheDir(); }
            } else {
                // 内置 files -> cache
                file = ctx.getFilesDir();
                if (file == null) { file = ctx.getCacheDir(); }
            }
            if (file != null) {
                File fileDir = new File(file, folderName);
                if (!fileDir.exists()) { fileDir.mkdirs(); }
                return fileDir;
            }
        }
        return null;
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的cache->files文件夹；
     * SD卡不可用下，返回内存存储应用下的cache->files文件夹；
     */
    public static File appCreateCache(Context ctx, String folderName) {
        if (ctx != null) {
            File file = null;
            if (isSdCardExist()) {
                // SD卡 cache->files
                file = ctx.getExternalCacheDir();
                if (file == null) { file = ctx.getExternalFilesDir(null); }
            } else {
                // 内置 cache->files
                file = ctx.getCacheDir();
                if (file == null) { file = ctx.getFilesDir(); }
            }
            if (file != null) {
                File fileDir = new File(file, folderName);
                if (!fileDir.exists()) { fileDir.mkdirs(); }
                return fileDir;
            }
        }
        return null;
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的files->cache文件夹；
     * SD卡不可用下，返回内存存储应用下的files->cache文件夹；
     */
    public static File appCreateFile(Context ctx, String folderName, String fileName) {
        File pathFile = appCreateFolder(ctx, folderName);
        if (pathFile != null) {
            return new File(pathFile, fileName);
        }
        return null;
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的cache文件夹路径；
     * SD卡不可用下，返回内存存储应用下的cache文件夹路径；
     */
    public static String appCachePath(Context ctx) {
        File file = appCacheFolder(ctx);
        return file != null ? file.getAbsolutePath() : "";
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的files文件夹；
     * SD卡不可用下，返回内存存储应用下的files文件夹；
     */
    public static File appFilesFolder(Context ctx) {
        if (ctx != null) {
            if (!isSdCardExist())
                return ctx.getFilesDir();
            else
                return ctx.getExternalFilesDir(null);
        }
        return null;
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @return 优先返回SD卡下，应用的files文件夹路径；
     * SD卡不可用下，返回内存存储应用下的files文件夹路径；
     */
    public static String appFilesPath(Context ctx) {
        File file = appCacheFolder(ctx);
        return file != null ? file.getAbsolutePath() : "";
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @param type {@code null}
     *             {@link Environment#DIRECTORY_MUSIC},
     *             {@link Environment#DIRECTORY_PODCASTS},
     *             {@link Environment#DIRECTORY_RINGTONES},
     *             {@link Environment#DIRECTORY_ALARMS},
     *             {@link Environment#DIRECTORY_NOTIFICATIONS},
     *             {@link Environment#DIRECTORY_PICTURES}, or
     *             {@link Environment#DIRECTORY_MOVIES}.
     * @return 优先返回SD卡下，应用的files文件夹路径；
     * SD卡不可用下，返回内存存储应用下的files文件夹路径；
     */
    public static File appSDCardFilesFolder(Context ctx, @Nullable String type) {
        if (ctx != null && isSdCardExist())
            return ctx.getExternalFilesDir(type);

        return null;
    }

    /**
     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
     *
     * @param type {@code null}
     *             {@link Environment#DIRECTORY_MUSIC},
     *             {@link Environment#DIRECTORY_PODCASTS},
     *             {@link Environment#DIRECTORY_RINGTONES},
     *             {@link Environment#DIRECTORY_ALARMS},
     *             {@link Environment#DIRECTORY_NOTIFICATIONS},
     *             {@link Environment#DIRECTORY_PICTURES}, or
     *             {@link Environment#DIRECTORY_MOVIES}.
     * @return 优先返回SD卡下，应用的files文件夹路径；
     * SD卡不可用下，返回内存存储应用下的files文件夹路径；
     */
    public static String appSDCardFilesPath(Context ctx, @Nullable String type) {
        File sdFile = appSDCardFilesFolder(ctx, type);

        return sdFile != null ? sdFile.getAbsolutePath() : "";
    }

    /**
     * @return 返回文件夹 {@link File}
     */
    @Nullable
    public static File getFolder(String folderPath) {
        File folder = null;
        if (!TextUtils.isEmpty(folderPath)) {
            folder = new File(folderPath);
            if (!folder.exists()) folder.mkdirs();
        }
        return folder;
    }

    /**
     * @return 返回文件 {@link File}
     */
    public static @Nullable File getFile(String filePath) {
        File file = null;
        if (!TextUtils.isEmpty(filePath)) {
            file = new File(filePath);
            if (!file.exists()) {
                File folder = getFolder(file.getParent());
                if (folder != null) {
                    try {
                        file.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                        file = null;
                    }
                } else {
                    file = null;
                }
            }
        }
        return file;
    }

    /**
     * 判断文件是否存在
     */
    public static boolean isFileExists(final File file) {
        return file != null && file.exists();
    }

    /**
     * 递归删除文件、文件夹下的所有数据
     */
    public static void deleteFile(File file) {
        if (file == null || !file.exists()) return;
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files.length > 0) {
                for (File subFile : files) deleteFile(subFile);
            }
        }
        file.delete();
        Logger.d("delete file：" + file.getAbsolutePath());
    }

    /**
     * 递归删除文件、文件夹下的所有数据
     */
    public static void deleteFile(String filePath) {
        if (TextUtils.isEmpty(filePath)) return;
        File file = new File(filePath);
        if (file != null) deleteFile(file);
    }

    /**
     * 往磁盘中写入文件
     */
    public static File writeToDisk(InputStream is, Context ctx, String dir, String name) {
        final File file = FileUtil.appCreateFile(ctx, dir, name);
        if (file != null) {
            return writeToDisk(is, file);
        }
        return file;
    }

    /**
     * 往磁盘中写入文件
     */
    public static File writeToDisk(InputStream is, File file) {
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(is);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);

            byte data[] = new byte[1024 * 4];

            int count;
            while ((count = bis.read(data)) != -1) {
                bos.write(data, 0, count);
            }

            bos.flush(); fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bos != null) { bos.close(); }
                if (fos != null) { fos.close(); }
                if (bis != null) { bis.close(); }
                if (is != null) { is.close(); }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }

    /**
     * 得到文件夹大小
     */
    public static long getFolderSize(File folder) {
        long size = 0;
        if (folder != null && folder.exists()) {
            try {
                File[] files = folder.listFiles();
                for (File file : files) {
                    if (file.isDirectory()) {
                        size = size + getFolderSize(file);
                    } else {
                        size = size + file.length();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return size;
    }

    /**
     * @return 返回文件、文件夹的大小
     */
    public static long getFolderSize(String folderName) {
        if (!TextUtils.isEmpty(folderName)) {
            File folder = new File(folderName);
            if (folder != null) {
                if (folder.isDirectory())
                    return getFolderSize(folder);
                else
                    return folder.length();
            }
        }
        return 0l;
    }

    /**
     * @return 返回文件、文件夹的大小
     */
    public static String formatFileSize(File file) {
        return formatSize(getFolderSize(file));
    }

    /**
     * @return 返回文件、文件夹的大小
     */
    public static String formatFileSize(String file) {
        return formatSize(getFolderSize(file));
    }

    /**
     * 读取raw目录中的文件,并返回为字符串
     */
    public static String getRawFile(Context ctx, @RawRes int rawId) {
        final Context appCtx = ctx.getApplicationContext();
        final InputStream inputStream = appCtx.getResources().openRawResource(rawId);
        final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
        final InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream);
        final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        final StringBuilder stringBuilder = new StringBuilder();
        try {
            String buffer = "";
            while ((buffer = bufferedReader.readLine()) != null) {
                stringBuilder.append(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) bufferedReader.close();
                if (inputStreamReader != null) inputStreamReader.close();
                if (bufferedInputStream != null) bufferedInputStream.close();
                if (inputStream != null) inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 读取assets目录下的文件,并返回字符串
     */
    public static String getAssetsFile(Context ctx, String fileName) {
        final Context appCtx = ctx.getApplicationContext();
        final AssetManager assetManager = appCtx.getAssets();
        InputStream inputStream = null;
        BufferedInputStream bufferedInputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            inputStream = assetManager.open(fileName);
            bufferedInputStream = new BufferedInputStream(inputStream);
            inputStreamReader = new InputStreamReader(bufferedInputStream);
            bufferedReader = new BufferedReader(inputStreamReader);
            String buffer;
            while ((buffer = bufferedReader.readLine()) != null) {
                stringBuilder.append(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) bufferedReader.close();
                if (inputStreamReader != null) inputStreamReader.close();
                if (bufferedInputStream != null) bufferedInputStream.close();
                if (inputStream != null) inputStream.close();
                if (assetManager != null) assetManager.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuilder.toString();
    }

    /**
     * @return 格式化大小，返回{B、KB、MB、GB、TB}
     */
    public static String formatSize(long size) {
        if (size <= 0) return 0 + " B";
        if (size < 1024) return size + " B";             // B

        double kiloByte = size * 1.0 / 1024;            // KB
        if (kiloByte < 1024) {
            BigDecimal result = new BigDecimal(Double.toString(kiloByte));
            return result.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + " KB";
        }

        double megaByte = kiloByte * 1.0 / 1024;        // MB
        if (megaByte < 1024) {
            BigDecimal result = new BigDecimal(Double.toString(megaByte));
            return result.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + " MB";
        }

        double gigaByte = megaByte * 1.0 / 1024;        // GB
        if (gigaByte < 1024) {
            BigDecimal result = new BigDecimal(Double.toString(gigaByte));
            return result.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + " GB";
        }

        double teraBytes = gigaByte * 1.0 / 1024;        // TB
        BigDecimal result = new BigDecimal(Double.toString(teraBytes));
        return result.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + " TB";
    }

}
